<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * 
 * @author fabiano
 */
abstract class MasterSupplier {
    
    private $code;
    private $name;
    private $account;
    private $method;
    private $services;    
    /*
     * This variable has the params that will be used on XML Search(all of them are from csv file)
     */
    private $search_params_map;
    /*
     * This variable has the params that will be used on XML Booking (all of them are from csv file)
     */    
    private $booking_params_map;    
    /*
     * this varible has the XML string that will be sent as request to supplier for searching
     */
    private $xmlSearch;
    /*
     * this varible has the XML string that will be sent as request to supplier for booking
     */    
    private $xmlBooking;
    
       
    abstract public function sendSearchRequest();
    abstract public function doCancelBooking();
    abstract public function buildSearchXML($params);
    abstract public function buildBookingXML($params);
    abstract public function buildCancelXML($params);
    abstract public function sendBookingRequest();
    
    /** 
     * Load csv file and set configurations to the application knows which service is availiable to this supplier
     * @param type $params 
     */
    
    public function __construct($params) {
            // store supplier configuration
        $this->setCode((string)$params["code"]);
        $this->setName((string)$params["name"]);
        $this->auth = array( "username_name"=>(string)$params->account->username["name"],
        	             "username_value"=> (string)$params->account->username["value"],
                             "password_name"=>(string)$params->account->password["name"],
	                     "password_value"=> (string)$params->account->password["value"] );
        
        if (!empty($params->account->reference["value"])) {
            $this->auth['reference_name']  = (string)$params->account->reference['name'];
            $this->auth['reference_value'] = (string)$params->account->reference['value'];
        }
    
	$this->setMethod((string)$params->method["type"]);
    
        $config_path = dirname(SUPPLIERS_CONFIG_FILE)."/";
        $services = array();
        $services["search"] = array("url"=>(string)$params->services->search["url"],
                                    "paramsmapfile"=>$config_path.$params->services->search->paramsmap["path"],
                                    "response_xslt"=>$config_path.$params->services->search->xsltresponse["path"] );
	
        $services["booking"] = array( "url"=>(string)$params->services->booking["url"],
                                      "paramsmapfile"=>$config_path.$params->services->booking->paramsmap["path"],
                                      "response_xslt"=>$config_path.$params->services->booking->xsltresponse["path"] );
    
        $services["details"] = array("url"=>(string)$params->services->details["url"],
                                     "paramsmapfile"=>$config_path.$params->services->details->paramsmap["path"] );

        $services['cancel_booking_info'] = array('url'=> (string)$params->services->cancel_booking_info['url'],
                                                 'paramsmapfile' => $config_path.$params->services->cancel_booking_info->paramsmap['path'],
                                                 'response_xslt' => $config_path.$params->services->cancel_booking_info->xsltresponse['path'],);

        $services['cancel_booking'] = array('url'=> (string)$params->services->cancel_booking['url'],
                                            'paramsmapfile' => $config_path.$params->services->cancel_booking->paramsmap['path'],
                                            'response_xslt' => $config_path.$params->services->cancel_booking->xsltresponse['path'],);  
        $this->setServices($services);
    }    
    
    public function getCode(){
        return $this->code;
    }
    
    public function setCode($code){
        $this->code = $code;
    }
    
   public function getName(){        
        return $this->name;
    }
    
    public function setName($name){
        $this->name = $name;
    }    
    
    
    public function getMethod(){        
        return $this->method;
    }
    
    public function setMethod($method){
        $this->method = $method;
    }       
    
    public function getXmlSearch(){
        return $this->xmlSearch;
    }
    
    public function setXmlSearch($xmlSearch){     
        $this->xmlSearch = $xmlSearch;                 
    }
    
    public function getXmlBooking(){
        return $this->xmlBooking;
    }
    
    public function setXmlBooking($xmlBooking){     
        $this->xmlBooking = $xmlBooking;                 
    }
            
    public function getAccount(){        
        return $this->account;        
    }
    
    public function setAccount($account){
        $this->account = $account;
    }   
    
    public function setServices($services){        
        $this->services = $services;
    }
    
    public function getServices (){
        return $this->services;        
    }
    
    public function setSearchParamsMap($search_params_map){
        $this->search_params_map = $search_params_map;
    }
    
    public function getSearchParamsMap(){
        return $this->search_params_ma;
    }
    
    public function setBookingParamsMap($booking_params_map){
        $this->booking_params_map = $booking_params_map;
    }
    
    public function getBookingParamsMap(){
        return $this->booking_params_map;
    }
    
    protected function mapSearchParams($params){       
      
       $this->setSearchParamsMap($this->loadParamsFromMap('search'));
       return $this->mapParams($params, $this->search_params_map);        
        
    }   
    
    protected function mapBookingParams($params) {
       $this->setBookingParamsMap($this->loadParamsFromMap('booking'));
       return $this->mapParams($params, $this->booking_params_map);        
    }

    protected function loadParamsFromMap($map) {
       $params_map = array();
       $fh = fopen($this->services[$map]["paramsmapfile"], "r");
       if(!$fh) throw new Exception("Can't load $map params map file for supplier $this->code");
       while($row = fgetcsv($fh, 1024)) {
         $param_props = array();
         $props_string = explode(";", $row[1]);
         foreach($props_string as $prop) {
           $ret = explode("=", $prop);
           $param_props[$ret[0]] = $ret[1];
         }
         $params_map[$row[0]] = $param_props;
       }
       return $params_map;
    }
    
    private function preparedParamsRooms($params){
       $rooms = array();
       for ($index = 1; $index <= $params['no_rooms']; $index++) {
          $rooms['room_'.$index] = array ('Adults' => $params['room_adults_'.$index],
                                          'Children' => $params['room_children_'.$index]);
       }
       return $rooms;
    }
    
    protected function mapParams($params, $map) {
       $result = array();
       $params['rooms'] = $this->preparedParamsRooms($params);
       foreach($map as $param=>$props) {
         if(isset($props["fname"])) {
           if(isset($params[$props["fname"]])) {
            // if we have value to read from user form - read and format it          
            $value = $params[$props["fname"]];
            if(isset($props["type"])) {
              switch($props["type"]) {
                case "date":
                  // format date field according to format
                  if(isset($props["format"])) {
                    $value = date($props["format"], $value);
                  }
                  else {
                    $value = date(SUPPLIER_DEFAULT_DATE_FORMAT, $value);
                  }
                break;
              }
            }        
            $result[$param] = $value;
          }
          else {
            // we have no value from user form, try to find default value          
            if(isset($props["default"])) {
              $result[$param] = $props["default"];
            }
            // if no default value - skip parameter
          }
        }  
        else {
          // if no fname parameter set - try to use default value for current parapeter
          if(isset($props["default"])) {
            $result[$param] = $props["default"];
          }
        }
      }
      return $result;
  }  
  
    public function getServicesByKey($key){
      return $this->services[$key];
  }
   
    public function getServiceUrlByKey($key){
      return $this->services[$key]['url'];
  }
  
    public function getServiceXsltPathByKey($key){
      return $this->services[$key]['response_xslt'];
  }
   
    public function parseXmlSearchResult($xml){
        $this->xmlLog($xml, 'response', MODE_RUN);
        $native = $this->bindingXmlToNative($xml);
        $results = array();
        $results["hotels"] = array();   
        foreach($native as $supplier=>$xml) {        
          $xo = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
          if($xo && isset($xo->session)) {
            $session_id = trim($xo->session->id);
            $currency = trim($xo->session->Currency);
            foreach($xo->session->Hotel as $value) {
              $hotel = (array)$value;
              $rooms = $hotel["Rooms"];              
              unset($hotel["Rooms"]);
              $hotel["session_id"] = $session_id;
              $hotel["currency"] = (! isset($currency) ? $currency : "EUR");
              
              //get what supplier this result is from.          
              $hotel["supplier_code"] = $supplier;
              
              if(isset($rooms->Room_1)) {
                $hotel["room_sets"][1]["adults"] = intval($rooms->Room_1[0]->Passengers->Adults);
                $hotel["room_sets"][1]["children"] = intval($rooms->Room_1[0]->Passengers->Children);
                $i = 0;
                
                foreach ($rooms->Room_1 as $key => $value) {
                  $i++; 
                  $hotel["room_sets"][1]["rooms"][(string)$value->Room->ID .'_'.$i] = (array)$value->Room;
                    
                }
              }
              if(isset($rooms->Room_2)) {
                $hotel["room_sets"][2]["adults"] = intval($rooms->Room_2[0]->Passengers->Adults);
                $hotel["room_sets"][2]["children"] = intval($rooms->Room_2[0]->Passengers->Children);
                $i = 0;
                foreach ($rooms->Room_2 as $key => $value) {
                  $i++; 
                  $hotel["room_sets"][2]["rooms"][(string)$value->Room->ID .'_'.$i] = (array)$value->Room;                
                }
              }
              if(isset($rooms->Room_3)) {
                $hotel["room_sets"][3]["adults"] = intval($rooms->Room_3[0]->Passengers->Adults);
                $hotel["room_sets"][3]["children"] = intval($rooms->Room_3[0]->Passengers->Children);
                $i = 0;

                foreach ($rooms->Room_3 as $key => $value) {
                  $i++; 
                  $hotel["room_sets"][3]["rooms"][(string)$value->Room->ID .'_'.$i] = (array)$value->Room;                
                }
              }
              $hotel["facility"] = (string)$hotel["facility"];
              $results["hotels"][] = $hotel;
            }
          }
        }        
    
          return $results;  
            
    }
    
    private function bindingXmlToNative($xml){
            
        $xp = new XsltProcessor();
        // create a DOM document and load the XML datat
        $xml_doc = new DomDocument;
        // create a DOM document and load the XSL stylesheet
        $xsl = new DomDocument;
        // native results storage
        $native = array();
// Starting here the XML parser. 
        foreach ($xml as $supplier=>$result) {
            $xsl->load($this->getServiceXsltPathByKey("search"));
            // import the XSL styelsheet into the XSLT process
            $xp->importStylesheet($xsl);      
            if (@$xml_doc->loadXML($result)) {
                $native[$supplier] = $xp->transformToXml($xml_doc);
            } else {
                // signal error
                $GLOBALS['note'] = array('type'=>'neg', 'message'=>'System error occured. Please do another search. 
                                                                    If error repeats, please contact site\'s administration');
                $this->log_error($supplier, $search_queries[$supplier]."\n\n".$result);
                $native[$supplier] = "";
            }
        }
        return $native;
    }
    
    private function bindingXmlBookingToNative($xml){
       $this->xmlLog($xml, 'response_booking', MODE_RUN);
       $xp = new XsltProcessor();
       $xml_doc = new DomDocument;
       $xsl = new DomDocument;
       $xsl->load($this->getServiceXsltPathByKey("booking"));
       $xp->importStylesheet($xsl);          
       $result = '';
       if(@$xml_doc->loadXML($xml)){
           $result = $xp->transformToXml($xml_doc);
       } else {
           $result["success"] = "false";
           $result["error_msg"] = "System error: supplier unavailable. Please try to book later or contact site's administration";
       }
         
       return $result; 
    }
    
    public function parseXmlBookingResult($xml){
       $native = $this->bindingXmlBookingToNative($xml);
       $result = array();
       if (!(is_array($xml) && isset($xml["success"]) && $xml['success'] == 'false')) {
          $xo = simplexml_load_string($native, 'SimpleXMLElement', LIBXML_NOCDATA);
          $result["success"] = (string)$xo->Success;
          $result["booking_ref"] = (string)$xo->Booking_ref;
          $result["voucher_url"] = (string)$xo->Voucher_Url;
          $result["error_msg"] = (string)@$xo->Error_Msg; 
          $result["exception"] = (string)@$xo->Exception; 
          return $result;   
       }   
       else return $xml;   
    }
    
    public function xmlLog($xml, $type, $modeRun){
        if ($modeRun == 'debbug'){
            $microseconds = (string) microtime(true);        
            file_put_contents("logs/{$this->getCode()}_{$microseconds}_{$type}.xml", $xml);
        }
    }
    
    
}
?>
